import math
from typing import Iterable
from ._globals import EPSILON


class Vector(Iterable):
    """实现我们自定义的向量类"""

    def __init__(self, lst: Iterable):
        # 在python中我们默认使用_xxx作为内部私有的变量. 这是一个约定
        self._values = list(lst)

    @classmethod
    def zeros(cls: 'Vector', dim: int) -> 'Vector':
        """返回一个dim维的零向量"""
        return cls([0] * dim)

    # region 向量的基础运算操作
    def __add__(self: 'Vector', other: 'Vector') -> 'Vector':
        assert len(self) == len(
            other), "Error in adding. Length of vectors must be same."
        # self 是一个Iterable, zip会iter(self) 获取 _values的iter
        # self = [1, 2, 3], other = [2, 3, 4]
        # zip(self, other) => [(1, 2), (2, 3), (3, 4)]
        return Vector([i + j for i, j in zip(self, other)])

    def __sub__(self: 'Vector', other: 'Vector') -> 'Vector':
        assert len(self) == len(
            other), "Error in subing. Length of vectors must be same."
        return Vector([i - j for i, j in zip(self, other)])

    def __mul__(self: 'Vector', scalar: int | float) -> 'Vector':
        """返回数量乘法的结果向量: self * scalar"""
        return Vector([i * scalar for i in self])

    def __rmul__(self: 'Vector', scalar: int | float) -> 'Vector':
        """返回数量乘法的结果向量: scalar * self"""
        return self.__mul__(scalar)

    def __pos__(self):
        """返回向量取正的结果向量"""
        return 1 * self

    def __neg__(self):
        """返回向量取负的结果向量"""
        print("__neg__ running")
        return -1 * self

    def __truediv__(self, other: float | int) -> 'Vector':
        """数除 self / other"""
        return self * (1 / other)

    def norm(self: 'Vector'):
        """返回向量的摸"""
        return math.sqrt(sum(i ** 2 for i in self))

    def normalize(self):
        """返回当前向量的单位向量, """
        if self.norm() < EPSILON:
            raise ZeroDivisionError("normalize error! norm is zero")
        return self / self.norm()

    def dot(self: 'Vector', other: 'Vector') -> int | float:
        """向量的点乘/内积"""
        assert len(self) == len(
            self), "Error in dot product. Length of vectors must be same"
        return sum(i * j for i, j in zip(self, other))

    # endregion

    def __iter__(self):
        """返回该类的迭代器"""
        # 使得当前类实例变成 Iterable 实现类
        return iter(self._values)

    def __getitem__(self, index):
        # 实现 self[index]方式的求值. 同时for循环会在没有实现__iter__方法时, 调用该方法
        print(f"Accessing index {index}")
        return self._values[index]

    def __setitem__(self, index, val):
        # 实现 self[index]方式的赋值
        assert index < len(
            self), "Error in set item. index must neg the vector dims"
        self._values[index] = val

    def __len__(self):
        """返回向量的维度"""
        return len(self._values)

    def __repr__(self):
        return f"Vector({self._values})"

    def __str__(self):
        """调用print时 返回这样的形式 (1, 2, 3)"""
        return f"({", ".join(str(i) if type(i) != float else f"{i:.2f}" for i in self._values)})"
